//: -L+matrixssl.lib+Advapi32.lib+Ws2_32.lib

import 
	tango.core.Traits,
	tango.net.device.Berkeley,
	tango.sys.win32.WsaSock ,
	tango.sys.win32.UserGdi ;

//alias UINT ALG_ID;
//alias ULONG HCRYPTPROV, HCRYPTKEY, HCRYPTHASH;
//alias PVOID HCERTSTORE, HCRYPTMSG, HCERTCHAINENGINE;

alias ULONG_PTR	HCRYPTPROV;

struct sslKeys_t ;
struct ssl_t ;
struct psX509Cert_t;
struct sslSessionId_t;
struct tlsExtension_t;

enum : int {
	PS_INTERRUPT_FAIL	= -14 ,
	PS_TIMEOUT_FAIL	= -13 ,
	PS_PROTOCOL_FAIL	= -12 ,
	PS_DISABLED_FEATURE_FAIL	= -11 ,
	PS_UNSUPPORTED_FAIL	= -10 ,
	PS_LIMIT_FAIL	= -9 ,
	PS_MEM_FAIL	= -8 ,
	PS_PLATFORM_FAIL	= -7 ,
	PS_ARG_FAIL	= -6 ,
	PS_FAILURE	= -1 ,
	PS_SUCCESS	= 0 ,
	PS_FALSE		= 0 ,
	PS_TRUE		= 1 ,
	PS_CORE_IS_OPEN	= 1 ,
	
	MATRIXSSL_SUCCESS	= PS_SUCCESS ,
	MATRIXSSL_ERROR	= PS_PROTOCOL_FAIL ,
	MATRIXSSL_REQUEST_SEND	= 1 ,
	MATRIXSSL_REQUEST_RECV	= 2 ,
	MATRIXSSL_REQUEST_CLOSE	= 3 ,
	MATRIXSSL_APP_DATA	= 4 ,
	MATRIXSSL_HANDSHAKE_COMPLETE	= 5 ,
	MATRIXSSL_RECEIVED_ALERT	= 6 ,
}

extern(C){
	int printf(char*,...);
	
	/*	MatrixSSL Public API set	*/
	int matrixSslOpen();
	int matrixSslClose();
	int matrixSslNewKeys(sslKeys_t**);
	void matrixSslDeleteKeys(sslKeys_t*);
	
	void matrixSslDeleteSession(ssl_t*);
	int matrixSslGetReadbuf(ssl_t*, ubyte** buf);
	int matrixSslGetOutdata(ssl_t*, ubyte** buf);
	int matrixSslGetWritebuf(ssl_t*, ubyte** buf, uint reqLen);
	int matrixSslEncodeWritebuf(ssl_t*, uint len);
	int matrixSslSentData(ssl_t*, uint bytes);
	int matrixSslReceivedData(ssl_t*, uint bytes, ubyte** ptbuf, uint* ptlen);
	int matrixSslProcessedData(ssl_t*, ubyte** ptbuf, uint* ptlen);
	int matrixSslEncodeClosureAlert(ssl_t*);
	
	int matrixSslLoadRsaKeys(sslKeys_t*, char* certFile,char* privFile, char* privPass, char* trustedCAFile);
	
	int matrixSslLoadRsaKeysMem(sslKeys_t*, ubyte* certBuf, int certLen, ubyte* privBuf, int privLen, ubyte* trustedCABuf, int trustedCALen);
	
	
	/*	MatrixSSL Advanced feature public APIS	*/
	void	matrixSslGetAnonStatus(ssl_t*, int* anonArg);
	alias int function(ssl_t*, psX509Cert_t* cert, int alert) CertCb ;
	int matrixSslEncodeRehandshake(ssl_t*, sslKeys_t*, CertCb certCb, uint sessionOption, uint cipherSpec);
	
	/*	MatrixSSL Client side APIs	*/
	//#define	matrixSslInitSessionId(SID) SID.cipherId = SSL_NULL_WITH_NULL_NULL
	
	alias int function(ssl_t *ssl, ushort extType, ushort extLen, void* e) ExtCb ;
	int matrixSslNewClientSession(ssl_t**, sslKeys_t*, sslSessionId_t* sid, uint cipherSpec, CertCb certCb, tlsExtension_t *extensions, ExtCb extCb );
	
	/* Hello extension support.  RFC 3546 */
	int matrixSslNewHelloExtension(tlsExtension_t** extension);
	int matrixSslLoadHelloExtension(tlsExtension_t* extension, ubyte *extData, uint length, uint extType);
	void matrixSslDeleteHelloExtension(tlsExtension_t* extension);
	
	/*	MatrixSSL Server side APIs	*/
	int matrixSslNewServerSession(ssl_t**, sslKeys_t*, CertCb certCb);
}

const DWORD CRYPT_VERIFYCONTEXT	= 0xf0000000 ;
const DWORD PROV_RSA_FULL			= 1 ;

void main(){
	WSADATA wd = void;
	call!(WSAStartup)(0x0202, &wd);
	call!(matrixSslOpen)();
	sslKeys_t* keys;
	call!(matrixSslNewKeys)(&keys);
	printf("keys = %x\n", keys );
	call!(matrixSslDeleteKeys)(keys);
	call!(matrixSslClose)();
}

char[] AliasName(alias F)(){
	char[] name	= (&F).stringof[2..$] ;
	char[] name_	= new char[ name.length+1] ;
	foreach(int i, c;name) name_[i] = c;
	name_[$-1]	= 0 ;
	return name_;
}

void dump(alias F)(){
	const n			= AliasName!(F)() ;
	printf("%s:%x \n", n.ptr , &F) ;
}

void call(alias F, T...)(T t){
	const n			= AliasName!(F)() ;
	alias ReturnTypeOf!(F) Ret;
	static if( is( Ret == void ) ){
		F(t);
		printf("%s:%x 	= void \n", n.ptr , &F ) ;
	} else {
		Ret ret	= F(t);
		printf("%s:%x	= %d \n", n.ptr , &F, ret ) ;
	}
}
